#pragma once

#include <assert.h>
#include <memory>
#include <vector>
#include <iostream>
#include <map>
#include <thread>
#include <mutex>
#include <functional>

#include "Callbacks.h"
#include "Timestamp.h"
#include "Timer.h"

using namespace std;

class Channel;
class EPoller;
class TimerQueue;
class Buffer;
// one loop per thread每个线程只有一个EventLoop对象
class EventLoop {
public:
    typedef function<void()> Functor;

    EventLoop();
    ~EventLoop();

    void loop();
    void quit();

    void runInLoop(const Functor& cb);
    void queueInLoop(const Functor& cb);

    TimerId runAt(const Timestamp& time, const TimerCallback& cb);
    TimerId runAfter(double delay, const TimerCallback& cb);
    TimerId runEvery(double interval, const TimerCallback& cb);

    // internal use only
    void wakeup();
    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);

    void assertInLoopThread() { if (!isInLoopThread()) abortNotInLoopThread(); }
    bool isInLoopThread() const { return threadId_ == this_thread::get_id(); }
    std::thread::id getTid() { return threadId_; }

    void newConnection(int sockfd, 
        const ConnectionCallback& connectionCallback, 
        const MessageCallback& messageCallback);
    void insertInMap(const TcpConnectionPtr& conn);
    void removeInMap(const TcpConnectionPtr& conn);
    // void removeInMap(TcpConnection* conn);
    
private:
    void abortNotInLoopThread();

    void handleRead();  // waked up
    void doPendingFunctors();

    typedef vector<Channel*> ChannelList;

    bool looping_;
    bool quit_;
    bool callingPendingFunctors_;
    // const pid_t threadId_;
    const std::thread::id threadId_;

    shared_ptr<EPoller> poller_;
    shared_ptr<TimerQueue> timerQueue_;

    int wakeupFd_;
    shared_ptr<Channel> wakeupChannel_;
    ChannelList activeChannels_;

    mutex mutex_;
    vector<Functor> pendingFunctors_;

    typedef std::map<std::string, TcpConnectionPtr> ConnectionMap;
    ConnectionMap connections_;

    int connectionId_;

};